package com.bh.framework.aspectj;


import com.bh.common.annotation.DataDictClass;
import com.bh.common.annotation.Dict;
import com.bh.common.constant.Constants;
import com.bh.common.constant.Symbol;
import com.bh.common.utils.StringUtils;
import com.bh.system.service.ISysDictDataService;
import com.github.pagehelper.PageInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description: 字典aop类
 * @Author: slx
 * @Version: 1.0
 */

@Aspect
@Component
public class DictAspect {

    @Autowired
    private ISysDictDataService sysDictDataService;

    /**
     * 定义切点Pointcut
     *
     * @param dataDictClass
     */
    @Pointcut("@annotation(dataDictClass)")
    public void doDataDictClass(DataDictClass dataDictClass) {
    }

    @Around("@annotation(dataDictClass)")
    public Object doAround(ProceedingJoinPoint pjp, DataDictClass dataDictClass) throws Throwable {
        Object result = pjp.proceed();
        if (result != null) {
            this.parseDictText(result);
        }
        return result;
    }

    /**
     * 本方法针对返回对象为Result 的IPage的分页列表数据进行动态字典注入
     * 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ，table字典 code table text配合使用与原来jeecg的用法相同
     * 示例为SysUser   字段为sex 添加了注解@Dict(dictValue = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text，已字段名称加_dictText形式返回到前端
     * 例输入当前返回值的就会多出一个DictLabel字段
     * {
     * sex:1,
     * sexDictLabel:"男"
     * }
     */
    private void parseDictText(Object result) {
        //目前只渲染List 和 查询出的对象，暂时不处理Controller 层的分页数据
        if (result instanceof List && ((List<?>) result).size() > 0) {
            List<?> list = (List) result;
            addList(list);
        } else if (result instanceof PageInfo<?> && ((PageInfo<?>) result).getList().size() > 0) {
            List<?> list = ((PageInfo<?>) result).getList();
            addList(list);
        } else {
            addDictText(result, null);
        }
    }

    private void addList(List<?> list) {
        Map<String, Map<String, Object>> tableValues = new HashMap<>();
        Object one = list.get(0);
        for (Field field : StringUtils.getAllFields(one)) {
            //update-end--Author:scott  -- Date:20190603 ----for：解决继承实体字段无法翻译问题------
            if (field.getAnnotation(Dict.class) != null) {
                String code = field.getAnnotation(Dict.class).dictValue();
                String text = field.getAnnotation(Dict.class).dictLabel();
                String table = field.getAnnotation(Dict.class).dictTable();

                field.setAccessible(true);
                if (StringUtils.isNotBlank(table)) {
                    Set<String> keys = new HashSet<>();
                    list.forEach(obj -> {
                        try {
                            if (field.get(obj) != null) {
                                keys.addAll(Arrays.asList(field.get(obj).toString().split(Symbol.COMMA)));
                            }
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    });
                    //获取所有list的值
                    if (keys.size() > 0) {
                        Map<String, Object> tableValue = sysDictDataService.selectTableDictLabelByValues(table, text, code, keys);
                        if (tableValue != null && tableValue.size() > 0) {
                            tableValues.put(table + field.getName(), tableValue);
                        }
                    }
                }
            }
        }

        for (Object record : list) {
            addDictText(record, tableValues);
        }
    }


    private void addDictText(Object record, Map<String, Map<String, Object>> tableValues) {
        if (record == null) {
            return;
        }
        Class<?> c = record.getClass();
        Class<?> p = c.getSuperclass();
        Map<String, Object> dtMap = new HashMap<>();
        Field mapField = null;
        Field[] fields = StringUtils.getAllFields(record);
        for (Field field : fields) {
            if (field.getAnnotation(Dict.class) != null) {
                String codeField = field.getAnnotation(Dict.class).dictValue();
                String textField = field.getAnnotation(Dict.class).dictLabel();
                String table = field.getAnnotation(Dict.class).dictTable();
                String alias = field.getAnnotation(Dict.class).dictAlias();
                try {
                    field.setAccessible(true);
                    if (field.get(record) != null) {
                        String key = String.valueOf(field.get(record));
                        //翻译字典值对应的txt
                        String textValue = translateDictValue(codeField, textField, table, key, field.getName(), tableValues);
                        Field dictField = null;
                        String fieldName = field.getName() + Constants.DICT_LABEL_SUFFIX;
                        if (StringUtils.isNotBlank(alias)) {
                            fieldName = alias;
                        }
                        try {
                            dictField = c.getDeclaredField(fieldName);
                        } catch (Exception ignored) {}

                        try {
                            dictField = dictField == null ? p.getDeclaredField(fieldName):dictField;
                        } catch (Exception ignored) {}
                        // 如果找不到，则直接放入 map
                        if (dictField == null){
                            dtMap.put(fieldName, textValue);
                        } else {
                            dictField.setAccessible(true);
                            dictField.set(record, textValue);
                        }

                    }

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            if ("dtMap".equals(field.getName())){
                mapField = field;
            }
        }
        if(dtMap.size() > 0 && mapField != null) {
            try {
                mapField.set(record, dtMap);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 翻译字典文本
     *
     * @param codeField
     * @param text
     * @param table
     * @param key
     * @return
     */
    private String translateDictValue(String codeField, String text, String table, String key, String filed, Map<String, Map<String, Object>> tableValues) {
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        StringBuilder textValue = new StringBuilder();
        String[] keys = key.split(Symbol.COMMA);
        for (String k : keys) {
            String tmpValue = "";
            if (k.trim().length() == 0 || "null".equals(k.trim())) {
                continue; //跳过循环
            }
            if (!StringUtils.isEmpty(table)) {
                if (tableValues != null && tableValues.size() > 0) {
                    Map<String, Object> dictMap = tableValues.get(table + filed);
                    Object object = dictMap != null ? dictMap.get(k.trim()) : null;
                    if (object != null) {
                        //需要判断null
                        tmpValue = String.valueOf(((Map) object).get("text"));
                    }
                } else {
                    tmpValue = sysDictDataService.selectTableDictLabelByValue(table, text, codeField, k.trim());
                }
            } else {
                tmpValue = sysDictDataService.selectDictLabel(codeField, k.trim());
                if (StringUtils.isBlank(tmpValue)) {
                    tmpValue = sysDictDataService.selectJcDictLabelByType(codeField, k.trim());
                }
            }

            if (StringUtils.isNotEmpty(tmpValue)) {
                if (!"".equals(textValue.toString())) {
                    textValue.append(",");
                }
                textValue.append(tmpValue);
            }
        }
        return textValue.toString();
    }
}
